package cn.zzuli.edu.studywebsocket.config;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Date: 2021/3/12 18:32
 * @Author: 绯色下午茶
 * @Description:
 */
@ServerEndpoint("/imserver/{workerId}")
@Component
public class WebSocketServer {
    static Log log = LogFactory.get(WebSocketServer.class);
    /**
     * 用来记录当前在线人数，设计成线程安全的
     */
    private static int onLineCount = 0;
    /**
     * 存放每个客户端对应的webSocket对象
     * 使用线程安全的hashMap
     */
    static ConcurrentHashMap<Integer, WebSocketServer> concurrentHashMap = new ConcurrentHashMap<>();

    private Session session;
    /**
     * 接收workerId
     */
    private Integer workerId;

    /**
     * 连接成功调用的方法
     */
    @OnOpen
    public void open(Session session, @PathParam("workerId") int workerId) {
        this.session = session;
        this.workerId = workerId;

        /**
         * 如果之前存在，移除，新增
         */
        if (concurrentHashMap.containsKey(workerId)) {
            concurrentHashMap.remove(workerId);
            concurrentHashMap.put(workerId, this);
        } else {
            concurrentHashMap.put(workerId, this);

            /**
             * 在线数+1
             */
            addOnlineCount();

        }
        log.info("用户已连接：" + workerId + "  当前在线人数为：" + getOnlineCount());

        /**
         * 推送消息，提醒各管理有人上线
         */

    }

    /**
     * 连接关闭的方法
     */
    @OnClose
    public void onClose() {
        if (concurrentHashMap.containsKey(workerId)) {
            concurrentHashMap.remove(workerId);
            /**
             * 在线人数-1
             */
            subOnlineCount();
        }
        log.info("用户退出： " + workerId + " 当前在线人数为： " + getOnlineCount());
    }

    /**
     * 客户端发送消息调用的方法
     *
     * @return
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("用户消息:" + workerId + ",报文:" + message);
        if (StringUtils.isNotBlank(message)) {
            try {

                JSONObject jsonObject = JSON.parseObject(message);
                /**
                 * 追加发送人（防止串改
                 */
                jsonObject.put("fromWorkerId", this.workerId);
                Integer toWorkerId = jsonObject.getInteger("toWorkerId");

                /**
                 * 传给对用toWorkerId用户的webSocket
                 */
                if (null != toWorkerId && toWorkerId != 0 && concurrentHashMap.containsKey(toWorkerId)) {
                    concurrentHashMap.get(toWorkerId).sendMessage(jsonObject.toJSONString());
                } else {
                    log.error("请求的用户Id：" + toWorkerId + "不在这个服务器上");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @OnError
    public void onError(Session session, Throwable error) {
        log.error("用户错误:" + this.workerId + ",原因:" + error.getMessage());
        error.printStackTrace();
    }

    /**
     * 服务器主动推送数据
     *
     * @return
     */
    public void sendMessage(String message) throws Exception {
        this.session.getBasicRemote().sendText(message);
    }

    /**
     * 发送自定义消息
     *
     * @return
     */
    public static void sendInfo(String message, @PathParam("workerId") Integer workerId) throws Exception {
        log.info("发送消息到：" + workerId + " ，消息体：" + message);
        if (null != workerId && workerId != 0 && concurrentHashMap.containsKey(workerId)) {
            concurrentHashMap.get(workerId).sendMessage(message);
        } else {
            log.error("用户" + workerId + ",不在线！");
        }
    }

    public static synchronized int getOnlineCount() {
        return onLineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketServer.onLineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketServer.onLineCount--;
    }
}
